//! Remote actor communication module
//!
//! This module provides remote actor communication capabilities using gRPC,
//! allowing actors to communicate across network boundaries.

pub mod endpoint_manager;
pub mod remote_process;
pub mod server;
pub mod serialization;
pub mod config;

use std::sync::Arc;
use std::time::Duration;
use thiserror::Error;
use tracing::{debug, error, info, warn};
use anyhow::Result;

use crate::actor::{Actor, ActorError, PID, Props};
use crate::protos;
use crate::system::ActorSystem;
use crate::remote::endpoint_manager::EndpointManager;
use crate::remote::serialization::{MessageSerializer, ProtoSerializer, SerializerRegistry};

// Re-export public API
pub use self::config::RemoteConfig;

/// Remote actor errors
#[derive(Debug, Error)]
pub enum RemoteError {
    #[error("Failed to send message: {0}")]
    SendError(String),
    
    #[error("Failed to receive message: {0}")]
    ReceiveError(String),
    
    #[error("Serialization error: {0}")]
    SerializationError(String),
    
    #[error("Deserialization error: {0}")]
    DeserializationError(String),
    
    #[error("Connection error: {0}")]
    ConnectionError(String),
    
    #[error("Unknown error: {0}")]
    Unknown(String),
}

/// Remote actor system
pub struct RemoteSystem {
    /// Endpoint manager
    endpoint_manager: Arc<EndpointManager>,
    /// Serializer registry
    serializer_registry: Arc<SerializerRegistry>,
}

impl RemoteSystem {
    /// Create a new remote system
    pub fn new(system: ActorSystem, config: RemoteConfig) -> Self {
        let endpoint_manager = Arc::new(EndpointManager::new(system, config));
        let serializer_registry = Arc::new(SerializerRegistry::new());
        let proto_serializer = Arc::new(ProtoSerializer::new());
        serializer_registry.register(0, proto_serializer);
        
        Self {
            endpoint_manager,
            serializer_registry,
        }
    }
    
    /// Get the endpoint manager
    pub fn endpoint_manager(&self) -> Arc<EndpointManager> {
        Arc::clone(&self.endpoint_manager)
    }
    
    /// Get the serializer registry
    pub fn serializer_registry(&self) -> Arc<SerializerRegistry> {
        Arc::clone(&self.serializer_registry)
    }
}

impl Default for RemoteSystem {
    fn default() -> Self {
        let system = ActorSystem::new().expect("Failed to create actor system");
        let config = RemoteConfig::default();
        Self::new(system, config)
    }
}

/// Convert a PID to a protobuf message
pub fn pid_to_proto(pid: &PID) -> protos::actor::Pid {
    protos::actor::Pid {
        address: pid.address.clone(),
        id: pid.id.clone(),
    }
}

/// Convert a protobuf message to a PID
pub fn proto_to_pid(proto_pid: &protos::actor::Pid) -> PID {
    PID {
        address: proto_pid.address.clone(),
        id: proto_pid.id.clone(),
    }
}

/// Register a serializer for a message type
pub fn register_serializer(registry: Arc<SerializerRegistry>, id: u32, serializer: Arc<dyn MessageSerializer + 'static>) -> Result<(), RemoteError> {
    registry.register(id, serializer);
    Ok(())
}

/// Main Remote struct that serves as the entry point for remote functionality
pub struct Remote {
    /// The actor system
    system: ActorSystem,
    
    /// Remote configuration
    config: RemoteConfig,
    
    /// Remote server instance
    server: Option<server::RemoteServer>,
    
    /// Endpoint manager for handling remote connections
    endpoint_manager: Arc<endpoint_manager::EndpointManager>,
    
    /// Serializer registry for message serialization
    serializer_registry: Arc<serialization::SerializerRegistry>,
    
    /// Unique system ID
    system_id: String,
}

impl Remote {
    /// Creates a new Remote instance with the given actor system and configuration
    pub fn new(system: ActorSystem, config: RemoteConfig) -> Self {
        let system_id = uuid::Uuid::new_v4().to_string();
        let serializer_registry = Arc::new(serialization::SerializerRegistry::new());
        
        // Register the default ProtoSerializer
        let proto_serializer = Arc::new(serialization::ProtoSerializer::new());
        serializer_registry.register(0, proto_serializer);
        
        // Create the endpoint manager
        let endpoint_manager = Arc::new(endpoint_manager::EndpointManager::new(
            system.clone(),
            config.clone(),
        ));
        
        Self {
            system,
            config,
            server: None,
            endpoint_manager,
            serializer_registry,
            system_id,
        }
    }
    
    /// Starts the remote functionality
    pub async fn start(&mut self) -> Result<(), RemoteError> {
        info!("Starting remote with system ID: {}", self.system_id);
        
        // Create and start the remote server
        let mut server = server::RemoteServer::new(
            self.system.clone(),
            self.config.clone(),
        );
        
        server.start().await?;
        self.server = Some(server);
        
        info!("Remote started successfully");
        Ok(())
    }
    
    /// Stops the remote functionality
    pub async fn stop(&mut self) -> Result<(), RemoteError> {
        info!("Stopping remote");
        
        // Stop the server if it exists
        if let Some(server) = &mut self.server {
            server.stop().await?;
        }
        
        self.server = None;
        info!("Remote stopped successfully");
        Ok(())
    }
    
    /// Registers an actor kind that can be spawned remotely
    pub fn register<A: Actor + 'static>(&self, kind: &str, props: Props) -> Result<(), RemoteError> {
        if let Some(server) = &self.server {
            server.register::<A>(kind, props)?;
            info!("Registered actor kind: {}", kind);
            Ok(())
        } else {
            Err(RemoteError::Unknown("Remote server not started".to_string()))
        }
    }
    
    /// Spawns a remote actor
    pub async fn spawn_remote<A: Actor + 'static>(
        &self,
        address: &str,
        kind: &str,
        name: Option<&str>,
        timeout: Duration,
    ) -> Result<PID, RemoteError> {
        info!("Spawning remote actor of kind '{}' at address '{}'", kind, address);
        
        if let Some(server) = &self.server {
            let pid = server.spawn_remote::<A>(address, kind, name, timeout).await?;
            info!("Spawned remote actor with PID: {}", pid);
            Ok(pid)
        } else {
            Err(RemoteError::Unknown("Remote server not started".to_string()))
        }
    }
    
    /// Registers a serializer for custom message types
    pub fn register_serializer(&self, serializer: Arc<dyn serialization::MessageSerializer + 'static>) -> Result<(), RemoteError> {
        self.serializer_registry.register_serializer(serializer);
        Ok(())
    }
    
    /// Registers a type name for a specific type ID
    pub fn register_type_name<T: 'static>(&self, name: &str) -> Result<(), RemoteError> {
        self.serializer_registry.register_type_name::<T>(name);
        Ok(())
    }
}

impl From<RemoteError> for crate::actor::ActorError {
    fn from(err: RemoteError) -> Self {
        crate::actor::ActorError::MessageDeliveryFailed(err.to_string())
    }
}

impl From<tonic::transport::Error> for RemoteError {
    fn from(err: tonic::transport::Error) -> Self {
        RemoteError::ConnectionError(err.to_string())
    }
}

impl From<tonic::Status> for RemoteError {
    fn from(err: tonic::Status) -> Self {
        RemoteError::ConnectionError(err.to_string())
    }
}

impl From<prost::EncodeError> for RemoteError {
    fn from(err: prost::EncodeError) -> Self {
        RemoteError::SerializationError(err.to_string())
    }
}

impl From<prost::DecodeError> for RemoteError {
    fn from(err: prost::DecodeError) -> Self {
        RemoteError::DeserializationError(err.to_string())
    }
} 